﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Threading;

namespace RegexTester.Helpers
{
    public class TextBoxKeyDelayBehavior : Behavior<TextBox>
    {
        private DispatcherTimer _delayTimer;

        #region == Events ==
        
        #region E:TextChanged
        public event EventHandler<EventArgs> TextChanged;
        protected virtual void OnTextChanged(EventArgs e)
        {
            if (TextChanged != null)
                TextChanged(this, e);
        }
        #endregion

        #endregion

        #region == Bindable Properties ==

        #region CommandParameter
        public object CommandParameter
        {
            get { return (object)GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }
        public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(TextBoxKeyDelayBehavior), new PropertyMetadata(CommandParameterChanged));
        private static void CommandParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // Code for dealing with your property changes
        }
        #endregion

        #region Command
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(TextBoxKeyDelayBehavior), new PropertyMetadata(CommandChanged));
        private static void CommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // Code for dealing with your property changes
        }
        #endregion

        #region CommandDelay
        /// <summary>
        /// Gets or sets the delay (ms) after a key is pressed for the Command to be executed.
        /// </summary>
        /// <value>
        /// The command delay interval.
        /// </value>
        public int CommandDelay
        {
            get { return (int)GetValue(DelayProperty); }
            set { SetValue(DelayProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Delay.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DelayProperty =
            DependencyProperty.Register("Delay", typeof(int), typeof(TextBoxKeyDelayBehavior), new PropertyMetadata(1000));

        #endregion

        #endregion

        protected override void OnAttached()
        {
            base.OnAttached();

            _delayTimer = new DispatcherTimer();
            _delayTimer.Tick += DelayTimer_Tick;
            //AssociatedObject.KeyUp += AssociatedObject_KeyUp;
            AssociatedObject.TextChanged += AssociatedObject_TextChanged;
        }

        private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
        {
            var bindingExpression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
            bindingExpression.UpdateSource();

            _delayTimer.Stop();
            _delayTimer.Interval = TimeSpan.FromMilliseconds(Convert.ToDouble(this.CommandDelay));
            _delayTimer.Start();
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            _delayTimer.Stop();
            _delayTimer.Tick -= DelayTimer_Tick;
            //AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
            AssociatedObject.TextChanged -= AssociatedObject_TextChanged;
        }

        //private void AssociatedObject_KeyUp(object sender, KeyEventArgs e)
        //{
        //    var bindingExpression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
        //    bindingExpression.UpdateSource();
                        
        //    _delayTimer.Stop();
        //    _delayTimer.Interval = TimeSpan.FromMilliseconds(Convert.ToDouble(this.CommandDelay));
        //    _delayTimer.Start();
            
        //}

        private void DelayTimer_Tick(object sender, EventArgs e)
        {
            OnTextChanged(e);
            ExecuteCommand();

            _delayTimer.Stop();
        }

        private void ExecuteCommand()
        {
            if (Command != null)
            {
                if (CommandParameter == null)
                    Command.Execute(AssociatedObject.Text);
                else
                    Command.Execute(CommandParameter);
            }
        }

    } 
}
